#pragma once

#include "PresentParameters.h"
#include "D3DVertexElement.h"

namespace Vortex { namespace Wrapper { namespace Direct3D {
	ref class Direct3DSwapChain9;
	ref class Direct3DSurface9;
	ref class Direct3DTexture9;
	ref class Direct3DVertexBuffer9;
	ref class Direct3DIndexBuffer9;
	ref class Direct3DVertexShader9;
	ref class Direct3DPixelShader9;
	ref class Direct3DVertexDeclaration9;


	///<summary>Wrapper of IDirect3D9Device interface</summary>
	public ref class Direct3DDevice9 {
		IDirect3DDevice9* _handle;

	public:
		Direct3DDevice9(IDirect3DDevice9* device);

		~Direct3DDevice9();

		///<summary>Direct3DDevice handle</summary>
		property IntPtr Handle { IntPtr get() { return IntPtr(_handle); } }

		///<summary>Native Direct3DDevice handle</summary>
		property IDirect3DDevice9* NativeHandle { IDirect3DDevice9* get() { return _handle; } }


		///<summary>Returns amount of available texture memory in bytes</summary>
		UINT GetAvailableTextureMem();

		///<summary>Returns number of implicit swap chains</summary>
		UINT GetNumberOfSwapChains();

		///<summary>Get a swap chain by index</summary>
		HResult GetSwapChain(UINT iSwapChain, [Out] Direct3DSwapChain9^% result);

		///<summary>Get a depth-stencil surface</summary>
		HResult GetDepthStencilSurface([Out] Direct3DSurface9^% result);

		///<summary>Retrieves backbuffer of specified swapchain</summary>
		HResult GetBackBuffer(UINT iSwapChain, UINT BackBuffer, [Out] Direct3DSurface9^% result);

		///<summary>Initializes device for scene rendering</summary>
		HResult BeginScene();

		///<summary>Finalize device after scene rendering is complete</summary>
		HResult EndScene();

		///<summary>Clears rectangular content of current render target</summary>
		HResult Clear(Nullable<System::Drawing::Rectangle> rectangle, D3DClearFlags Flags, D3DCOLOR Color, float Z, DWORD Stencil);

		///<summary>Creates additional swap chain for rendering</summary>
		HResult CreateAdditionalSwapChain(PresentParameters% presentParams, [Out] Direct3DSwapChain9^% result);

		HResult CreateDepthStencilSurface(UINT Width, UINT Height, D3DFormat format, D3DMultisampleType MultiSample, 
			DWORD MultisampleQuality, bool Discard, [Out] Direct3DSurface9^% result);

		///<summary>Creates index buffer</summary>
		HResult CreateIndexBuffer(UINT length, D3DUsage usage, D3DFormat format, D3DPool pool, [Out] Direct3DIndexBuffer9^% result);

		///<summary>Creates vertex buffer</summary>
		HResult CreateVertexBuffer(UINT length, D3DUsage usage, D3DFVF fvf, D3DPool pool, [Out] Direct3DVertexBuffer9^% result);

		///<summary>Creates render target</summary>
		HResult CreateRenderTarget(UINT width, UINT height, D3DFormat format, D3DMultisampleType multisample, DWORD multisampleQuality, BOOL lockable, [Out] Direct3DSurface9^% result);

		///<summary>Creates texture</summary>
		HResult CreateTexture(UINT width, UINT height, UINT levels, D3DUsage usage, D3DFormat format, D3DPool pool, [Out] Direct3DTexture9^% result);

		///<summary>Creates vertex shader</summary>
		HResult CreateVertexShader(IntPtr pFunction, [Out] Direct3DVertexShader9^% result);

		///<summary>Creates pixel shader</summary>
		HResult CreatePixelShader(IntPtr pFunction, [Out] Direct3DPixelShader9^% result);

		///<summary>Creates vertex declaration based on definition of vertex elements</summary>
		HResult CreateVertexDeclaration(array<D3DVertexElement>^ elements, [Out] Direct3DVertexDeclaration9^% result);

		///<summary>Creates offscreen surface</summary>
		HResult CreateOffscreenPlainSurface(UINT width, UINT height, D3DFormat format, D3DPool pool, [Out] Direct3DSurface9^% result);

#pragma region Set methods

		///<summary>Set vertex declaration</summary>
		HResult SetVertexDeclaration(Direct3DVertexDeclaration9^ vertexDeclaration);

		///<summary>Sets current D3DFVF</summary>
		HResult SetFVF(D3DFVF fvf);

		///<summary>Sets depth-stencil surface</summary>
		HResult SetDepthStencilSurface(Direct3DSurface9^ surface);

		///<summary>Sets indices</summary>
		HResult SetIndices(Direct3DIndexBuffer9^ indexBuffer);

		///<summary>Sets render target</summary>
		HResult SetRenderTarget(DWORD renderTargetIndex, Direct3DSurface9^ renderTargetSurface);

		///<summary>Sets stream source</summary>
		HResult SetStreamSource(UINT streamNumber, Direct3DVertexBuffer9^ streamData, UINT offsetInBytes, UINT stride);

		///<summary>Sets texture to specified sampler</summary>
		HResult SetTexture(DWORD Sampler, Direct3DTexture9^ texture);

		///<summary>Sets scissor rectangle</summary>
		HResult SetScissorRect(System::Drawing::Rectangle rect);

		///<summary>Sets render state</summary>
		HResult SetRenderState(D3DRenderState state, DWORD value);

		///<summary>Sets boolean render state</summary>
		HResult SetRenderState(D3DRenderState state, bool value);

		///<summary>Sets sampler state type</summary>
		HResult SetSamplerState(DWORD sampler, D3DSamplerState state, DWORD value);

		///<summary>Sets vertex shader</summary>
		HResult SetVertexShader(Direct3DVertexShader9^ vertexShader);

		///<summary>Sets pixel shader</summary>
		HResult SetPixelShader(Direct3DPixelShader9^ pixelShader);

#pragma endregion

#pragma region Constant Control
		///<summary>Sets shader float constant</summary>
		HResult SetShaderConstantF(ShaderType type, UINT startRegister, float* pData, UINT vector4fCount);
		
		///<summary>Sets shader int constant</summary>
		HResult SetShaderConstantI(ShaderType type, UINT startRegister, int* pData, UINT vector4iCount);
		
		///<summary>Sets shader bool constant</summary>
		HResult SetShaderConstantB(ShaderType type, UINT startRegister, BOOL* pData, UINT boolCount);

#pragma endregion

#pragma region Lifetime Control

		///<summary>Tests cooperative level of device</summary>
		HResult TestCooperativeLevel();

		///<summary>Tries to reset device</summary>
		HResult Reset(PresentParameters% presentParams);

		///<summary>Present frame content</summary>
		HResult Present(Nullable<System::Drawing::Rectangle> sourceRect, Nullable<System::Drawing::Rectangle> destRect, IntPtr destWindowOverride);

#pragma endregion

#pragma region Lifetime Control

		///<summary>Draws a portion of indexed primitives</summary>
		HResult DrawIndexedPrimitive(D3DPrimitiveType Type, INT BaseVertexIndex, UINT MinIndex, UINT NumVertices, UINT StartIndex, UINT PrimitiveCount);

		///<summary>Draws a portion of primitives</summary>
		HResult DrawPrimitive(D3DPrimitiveType Type, UINT StartVertex, UINT PrimitiveCount);

		void DebugDraw();

		void DebugViewport();

#pragma endregion

		HResult SetCursorProperties(int hotSpotX, int hotSpotY, Direct3DSurface9^ surface);

		HResult ShowCursor(bool show);

		void SetCursorPosition(int x, int y);
	};




} } }